package jhavelogger.visitor;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import jhavelogger.models.AcceptedConnection;
import jhavelogger.models.UsernameLookup;
import jhavelogger.models.JHaveLog;
import jhavelogger.models.UidOperation;

/**
 * Base class for all log visitors.
 * @author Jared Schlicht
 */
public abstract class LogVisitor {
    /**
     * Finds the most specific implementation of the visit method using reflection.
     * Code adapted from http://surguy.net/articles/visitor-with-reflection.xml
     * 
     * @param log log object to visit
     * @return visit method object or null if no such method could be found
     */
    private Method getMethodToVisit(JHaveLog log) {
            Class logClass = log.getClass();  // the bottom-most class
            // Check through superclasses for a method that matches the required signature
            while(!logClass.equals(Object.class)) {
        	try {
        	    return this.getClass().getDeclaredMethod("visit", new Class[] { logClass });
        	} catch(NoSuchMethodException ex) {
        	    logClass = logClass.getSuperclass();
        	}
            }
	
	return null;
    }

    /**
     * Uses reflection to call more specific implementations of the visit method.
     * @param log the log to visit
     * @return the result of visiting the log.
     */
    public Object visit(JHaveLog log) {
	Method method = this.getMethodToVisit(log);
	if (method == null) {
	    return this.defaultVisit(log);
	} else {
	    try {
		return method.invoke(this, new Object[] { log });
	    } catch (IllegalArgumentException e) {
	    } catch (IllegalAccessException e) {
	    } catch (InvocationTargetException e) {
	    }
	}
	
	return null;
    }
    
    /**
     * This method is called when this class's visit method is not able to
     * find a suitable, more-specific visitor for the specified log file
     * @param log the log file that could not be visited
     * @return the result of the default visit operation
     */
    public abstract Object defaultVisit(JHaveLog log);
}
